#ifndef TRAFFIC_JAM_DIRECTION_HPP
#define TRAFFIC_JAM_DIRECTION_HPP

#include <vector>
#include "to_string.hpp"

/* 方向&方位相关的原语 */
namespace jam {

enum direction_t {
  East, South, West, North, Undefined
};

/* 仅仅用于储存和表示输入 */
class Directions: public std::vector<direction_t> {
 public:
  Directions(std::string &);
};

template<>
std::string to_string(const direction_t &);


/* ========
 * 编译期计算: 来向象限->去向象限(来向对面的象限)
 * ======== */
// 尤其是微某软的V某S不支持constexpr的时候

/* 路口结构
 *   ||
 *   ||
 * --NE--
 * --WS--
 *   ||
 *   ||
 */
template<direction_t dir>
struct _direction_value {
  const static direction_t value = dir;
};

/* ========
 * 计算象限方位x对面的象限y
 * ========
 */
template<direction_t _Dir>
struct opposite { };

#define SET_OPPOSITE(x, y) \
template<> \
struct opposite<x>: _direction_value<y> {};

SET_OPPOSITE(West, South);
SET_OPPOSITE(East, North);
SET_OPPOSITE(North, West);
SET_OPPOSITE(South, East);

#undef OPPOSITE_COUPLE
#undef X2Y

/* ========
 * 计算方位x左/右侧的方位y
 * 逆时针轮转的路口结构
 * ========
 */
template<direction_t>
struct rhs: _direction_value<Undefined> { };

template<direction_t>
struct lhs: _direction_value<Undefined> { };

#define SET_RIGHT(x, y) \
template <> \
struct rhs<x>: _direction_value<y> { }; \
template <> \
struct lhs<y>: _direction_value<x> { };

SET_RIGHT(East, North);
SET_RIGHT(North, West);
SET_RIGHT(West, South);
SET_RIGHT(South, East);

/* ========
 * X-Macros
 * ======== */

/* 按照 东-南-西-北-未定义 的顺序依次展开宏x */
#define ITERATE_ESWN(x) \
  x(East); x(South); x(West); x(North)
#define ITERATE_ESWNU(x) \
  ITERATE_ESWN(x); x(Undefined)
/* 逆向定义的宏 */
#define ITERATE_ENWS(x) \
 x(East); x(North); x(West); x(South)

/* 含参版本, 按照 (东,e)-(南,s)-(西,w)-(北,n)-(未定义,u) 的顺序依次展开宏 */
#define ITERATE_ESWN_ARG(x, e, s, w, n) \
  x(East, e);  x(South, s); x(West, w); x(North, n)
#define ITERATE_ESWNU_ARG(x, e, s, w, n, u) \
 ITERATE_ESWN_ARG(x, e, s, w, n); x(Undefined, u)

/* 按照 北-东-西-南 的顺序依次展开宏x */
#define ITERATE_NEWS(x) \
  x(North); x(East); x(West); x(South)

/* 含参版本, 按照 (北,n)-(东,e)-(西,w)-(南,s) 的顺序依次展开宏 */
#define ITERATE_NEWS_ARG(x, n, e, w, s) \
  x(North, n); x(East, e); x(West, w); x(South, s)

/* switch语句中 遇到Undefined时执行continue */
#define CONTINUE_ON_UNDEF \
  default: continue

/* 循环展开, 从start开始顺时针展开模板tpl并调用 */
template<direction_t start, direction_t end, template <direction_t> class tpl>
void _iterate_clockwise() {
  tpl<start>::function();
  if (start != end) {
    _iterate_clockwise<lhs<start>::value, end, tpl>();
  }
}

template<direction_t start, template <direction_t> class tpl>
void iterate_clockwise() {
  _iterate_clockwise<start, rhs<start>::value, tpl>();
}

}

#endif //TRAFFIC_JAM_DIRECTION_HPP
